package cn.mw.cmdb.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.extra.spring.SpringUtil;
import cn.mw.cmdb.entity.*;
import cn.mw.cmdb.enums.OperatorTypeDescEnum;
import cn.mw.cmdb.mongoMapper.ModelSpecificationMapper;
import cn.mw.cmdb.param.*;
import cn.mw.cmdb.service.ModelSpecificationService;
import cn.mw.cmdb.util.CMDBTool;
import cn.mw.cmdb.util.ExcelUtils;
import cn.mw.components.mongodb.entity.CriteriaOpsType;
import cn.mw.components.mongodb.entity.SearchParam;
import cn.mw.components.mongodb.entity.SubCondition;
import cn.mw.components.mongodb.tool.CriteriaWrapper;
import cn.mw.log.client.LogClientSimple;
import cn.mw.log.enums.BusinessLogType;
import cn.mw.log.enums.LogLevel;
import cn.mw.microMonitorCommon.api.user.MwUserApi;
import cn.mw.microMonitorCommon.constant.Constants;
import cn.mw.microMonitorCommon.security.dto.MwUser;
import cn.mw.microMonitorCommon.security.utils.SecurityUtils;
import cn.mw.microMonitorCommon.util.DateUtils;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.metadata.Head;
import com.alibaba.excel.metadata.data.WriteCellData;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.style.column.AbstractColumnWidthStyleStrategy;
import com.alibaba.nacos.common.utils.CollectionUtils;
import com.google.common.base.Strings;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Cell;
import org.springframework.context.MessageSource;
import org.springframework.context.i18n.LocaleContextHolder;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import static cn.mw.cmdb.enums.PageDescEnum.ModelManufacture;
import static cn.mw.cmdb.enums.PageDescEnum.ModelSpecification;
import static cn.mw.cmdb.service.impl.MwCustomRuleServiceImpl.patternStr;
import static cn.mw.cmdb.util.BaseUtil.getNowLocalTime;

@Slf4j
public class ModelSpecificationServiceImpl extends ModelBaseServiceImpl<ModelSpecificationInfo, SpecificationIdsParam> implements ModelSpecificationService {

    public static final String ID = "specificationService";

    private ModelSpecificationMapper modelSpecificationMapper;

    private CmdbServiceManage cmdbServiceManage;
    private LogClientSimple logClientSimple;

    private MwUserApi userApi;
    public ModelSpecificationServiceImpl(ModelSpecificationMapper modelSpecificationMapper, CmdbServiceManage cmdbServiceManage,MwUserApi userApi) {
        this.modelSpecificationMapper = modelSpecificationMapper;
        this.cmdbServiceManage = cmdbServiceManage;
        this.userApi = userApi;
    }

    public ModelSpecificationServiceImpl() {
        this.logClientSimple = SpringUtil.getBean(LogClientSimple.class);
    }

    @Override
    public ModelSpecificationInfo genObject() {
        return new ModelSpecificationInfo();
    }

    @Override
    Object doAdd(ModelSpecificationInfo param) throws Exception {
        CMDBTool.initCreateInfo(param);
        return modelSpecificationMapper.insert(param);
    }

    @Override
    boolean doUpdate(ModelSpecificationInfo param) throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelSpecificationInfo::getId).is(param.getId()));
        CMDBTool.initUpdateInfo(param);
        Update update = CMDBTool.genMongoUpdate(param, null, null);
        CMDBTool.updateFirst(modelSpecificationMapper, query, update);
        return true;
    }

    @Override
    boolean doRemove(ModelSpecificationInfo param) throws Exception {
        CMDBTool.remove(modelSpecificationMapper,param.getId(),ModelSpecificationInfo.class,true);
        return true;
    }

    @Override
    Object doBatchAdd(Object params) {
        MwUser user = SecurityUtils.getUser();
        String loginName = user.getUsername();
        List<ModelSpecificationInfo> paramList = new ArrayList<>();
        if(params !=null && params instanceof List){
            paramList = (List<ModelSpecificationInfo>) params;
            for (ModelSpecificationInfo param : paramList) {
                CMDBTool.initCreateInfo(param);
            }
            modelSpecificationMapper.insertAll(paramList);
        }

        return true;
    }

    @Override
    boolean doBatchUpdate(Object params) {
        return false;
    }

    @Override
    public ModelSpecificationInfo doSelectById(Object id) throws Exception {
        ModelSpecificationInfo info = modelSpecificationMapper.findById(id);
        return info;
    }
    public List<ModelSpecificationInfo> doSelectByIds(List<String> ids) throws Exception {
        Query query = genQueryByIds(ids);
        query.addCriteria(CriteriaWrapper.where(ModelSpecificationInfo::getDelFlag).is(false));
        List<ModelSpecificationInfo> list = modelSpecificationMapper.find(query);
        return list;
    }

    public List<ModelSpecificationInfo> getAllSpecificationInfos() throws Exception {
        Query query = new Query(CriteriaWrapper.where(ModelSpecificationInfo::getDelFlag).is(false));
        List<ModelSpecificationInfo> list = modelSpecificationMapper.find(query);
        return list;
    }

    @Override
    List<ModelSpecificationInfo> doSelectList(Object param) throws Exception {
        SpecificationSearchParam searchParam = (SpecificationSearchParam) param;
        searchParam.convert();
        Criteria criteria = genCriteria(searchParam);
        List<ModelSpecificationInfo> ret = CMDBTool.aggregateAuthorizedList(ModelSpecificationInfo.class, modelSpecificationMapper,criteria,searchParam);
        //获取所有厂商信息
        ModelVendorServiceImpl vendorService = (ModelVendorServiceImpl) cmdbServiceManage.getModelService(ModelVendorServiceImpl.ID);
        VendorSearchParam vendorSearchParam = new VendorSearchParam();
        vendorSearchParam.setOperation(SearchParam.keyword);
        vendorSearchParam.setKeywordValue("");
        List<ModelVendorInfo> vendorInfoList = vendorService.doSelectList(vendorSearchParam);
        Map<String, String> vendorMap = vendorInfoList.stream().filter(s -> s.getVendorCN() != null).collect(Collectors.toMap(s -> s.getId(), s -> s.getVendorCN()));
        for (ModelSpecificationInfo specInfo : ret) {
            if (vendorMap != null && vendorMap.containsKey(specInfo.getVendorId())) {
                //设置厂商名称
                specInfo.setVendor(vendorMap.get(specInfo.getVendorId()));
            }
        }
        return ret;
    }

    public List<ModelSpecificationInfoVo> dataListConvert(List<ModelSpecificationInfo> dataInfos) throws Exception {
        List<ModelSpecificationInfoVo> newList = new ArrayList<>();
        Set<Long> userIdSet = dataInfos.stream().flatMap(s -> Stream.of(s.getCreater(), s.getModifier())).filter(value -> value != null && value != 0l).collect(Collectors.toSet());
        List<Long> userIdList = new ArrayList<>(userIdSet);
        Map<String, String> userIdMap = null;
        if (CollectionUtil.isNotEmpty(userIdList)) {
            List<MwUser> usersByUserIds = userApi.getUsersByUserIds(userIdList);
            if (CollectionUtil.isNotEmpty(usersByUserIds)) {
                userIdMap = usersByUserIds.stream().collect(Collectors.toMap(k -> String.valueOf(k.getId()), MwUser::getNickName, (o1, o2) -> o1));
            }
        }
        for (ModelSpecificationInfo dataInfo : dataInfos) {
            ModelSpecificationInfoVo infoVo = new ModelSpecificationInfoVo();
            BeanUtil.copyProperties(dataInfo, infoVo);

            if (userIdMap != null && userIdMap.containsKey(infoVo.getCreater())) {
                infoVo.setCreater(userIdMap.get(infoVo.getCreater()));
            }
            if (userIdMap != null && userIdMap.containsKey(infoVo.getModifier())) {
                infoVo.setModifier(userIdMap.get(infoVo.getModifier()));
            }
            infoVo.setCreateTime(DateUtils.format(dataInfo.getCreateTime(),patternStr) );
            infoVo.setModificationTime(DateUtils.format(dataInfo.getModificationTime(),patternStr));
            newList.add(infoVo);
        }
        return newList;
    }




    @Override
    public List<ModelSpecificationInfo> querySpecificationByTempAndBrand(QuerySpecificationParam param) throws Exception {
        List<ModelSpecificationInfo> ret = new ArrayList<>();
        String templateName = param.getTemplateName();
        String brandId = param.getBrandId();
        if (Strings.isNullOrEmpty(templateName)) {
            return ret;
        }
        //获取模板信息
        TemplateSearchParam searchParam = new TemplateSearchParam();
        searchParam.addSubCondition(CMDBTool.getFieldName(ModelTemplateInfo::getTemplateName)
                , new SubCondition(CriteriaOpsType.is.name(), templateName));
        ModelTemplateServiceImpl modelService = (ModelTemplateServiceImpl) cmdbServiceManage.getModelService(ModelTemplateServiceImpl.ID);
        List<ModelTemplateInfo> modelTemplateList = modelService.doSelectList(searchParam);
        //获取模板中的规格型号Id集合
        Set<String> collect = modelTemplateList.stream().map(ModelTemplateInfo::getSpecificationId).collect(Collectors.toSet());
        SpecificationSearchParam searchSpecParam = new SpecificationSearchParam();
        if (collect != null) {
            searchSpecParam.addSubCondition(CMDBTool.getFieldName(ModelSpecificationInfo::getId)
                    , new SubCondition(CriteriaOpsType.in.name(), collect));
        }
        if (!Strings.isNullOrEmpty(brandId)) {
            searchSpecParam.addSubCondition(CMDBTool.getFieldName(ModelSpecificationInfo::getVendorId)
                    , new SubCondition(CriteriaOpsType.is.name(), brandId));
        }
        ret = doSelectList(searchSpecParam);
        return ret;
    }


    @Override
    boolean doBatchRemove(SpecificationIdsParam params) throws Exception {
        CMDBTool.remove(modelSpecificationMapper,params.getIds(),ModelSpecificationInfo.class,true);
        return true;
    }

    /**
     * 根据指定厂商下规格型号名称是否重复
     *
     * @param info
     * @return
     */
    @Override
    public boolean checkSpecificationName(ModelSpecificationInfo info) throws Exception {
        Query query = new Query(Criteria.where(CMDBTool.getFieldName(ModelSpecificationInfo::getVendorId)).is(info.getVendorId()));
        query.addCriteria(Criteria.where(CMDBTool.getFieldName(ModelSpecificationInfo::getSpecification)).is(info.getSpecification()));
        query.addCriteria(CriteriaWrapper.where(ModelSpecificationInfo::getDelFlag).is(false));
        List<ModelVendorInfo> list = modelSpecificationMapper.find(query);
        if (CollectionUtils.isNotEmpty(list)) {
            return true;
        }
        return false;
    }

    @Override
    public List<SpecificationExcelImportParam> importSpecificationByExcel(MultipartFile file, HttpServletResponse response) throws IOException {
        String fileName = file.getOriginalFilename();
        MwUser user = SecurityUtils.getUser();
        String loginName = user.getUsername();
        List<SpecificationExcelImportParam> failList = new ArrayList<>();
        if (null != fileName && (fileName.toLowerCase().endsWith(".xls") || fileName.toLowerCase().endsWith(".xlsx"))) {
            EasyExcel.read(file.getInputStream(), SpecificationExcelImportParam.class,
                    new SpecificationExcelImportListener(response, fileName, loginName, cmdbServiceManage,failList)).sheet().doRead();
        } else {
            log.error("没有传入正确的excel文件名", file);
        }
        return failList;
    }

    @Override
    public int exportSpecificationByExcel(SpecificationSearchParam param, HttpServletRequest request, HttpServletResponse response) throws Exception {
        int num = 0;
        ExcelWriter excelWriter = null;
        try {
            List<String> includeColumnFiledNames = new ArrayList<>();
            if (CollectionUtils.isEmpty(param.getHeader())) {
                includeColumnFiledNames.add(CMDBTool.getFieldName(SpecificationExcelImportParam::getSpecification));
                includeColumnFiledNames.add(CMDBTool.getFieldName(SpecificationExcelImportParam::getVendor));
                includeColumnFiledNames.add(CMDBTool.getFieldName(SpecificationExcelImportParam::getDescription));
                includeColumnFiledNames.add(CMDBTool.getFieldName(SpecificationExcelImportParam::getType));
                includeColumnFiledNames.add(CMDBTool.getFieldName(SpecificationExcelImportParam::getDeviceHeight));
            }else{
                includeColumnFiledNames = param.getHeader();
            }
            List<ModelSpecificationInfo> modelSpecificationInfos;
            if (param.isExportTemp()) {
                modelSpecificationInfos = new ArrayList<>();
                log.info("导出模板"+modelSpecificationInfos.size());
            } else {
                modelSpecificationInfos = doSelectList(param);
                log.info("导出模板"+modelSpecificationInfos.size());
            }
            log.info("导出模板字段："+includeColumnFiledNames);
            excelWriter = ExcelUtils.getExcelWriter("exportModelSpecification", response, SpecificationExcelImportParam.class);
            WriteSheet sheet = EasyExcel.writerSheet(0, "sheet" + 0)
                    .includeColumnFiledNames(includeColumnFiledNames)
                    .registerWriteHandler(ExcelUtils.writeTemplateStyle())
                    .registerWriteHandler(new SpecColumWithStyle())
                    .build();
            excelWriter.write(modelSpecificationInfos, sheet);
            if(CollectionUtils.isNotEmpty(modelSpecificationInfos)){
                num = modelSpecificationInfos.size();
            }
            log.info("导出成功");
        } catch (IOException e) {
            log.error("导出失败{}", e);
        } finally {
            if (null != excelWriter) {
                excelWriter.finish();
            }
        }
        return num;
    }

    private class SpecColumWithStyle extends AbstractColumnWidthStyleStrategy {
        @Override
        protected void setColumnWidth(WriteSheetHolder writeSheetHolder, List<WriteCellData<?>> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
            if (isHead) {
                writeSheetHolder.getSheet().setColumnWidth(cell.getColumnIndex(), 6000);
            }
        }
    }

    /**
     * 新增异常日志记录
     *
     * @param param
     */
    public void addRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelSpecificationInfo) {
            ModelSpecificationInfo info = (ModelSpecificationInfo) param;
            name = info.getSpecification();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.add.getCname() + ModelSpecification.getDesc(),
                        OperatorTypeDescEnum.add.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 修改异常日志记录
     *
     * @param param
     */
    public void updateRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelSpecificationInfo) {
            ModelSpecificationInfo info = (ModelSpecificationInfo) param;
            name = info.getSpecification();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.update.getCname() + ModelSpecification.getDesc(),
                        OperatorTypeDescEnum.update.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 删除异常日志记录
     *
     * @param param
     */
    private void removeRecordMethod(Object param) {
        String name = "";
        if (param != null && param instanceof ModelSpecificationInfo) {
            ModelSpecificationInfo info = (ModelSpecificationInfo) param;
            name = info.getSpecification();
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.remove.getCname() + ModelSpecification.getDesc(),
                        OperatorTypeDescEnum.remove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 批量新增异常日志记录
     *
     */
    private void batchAddRecordMethod(Object params) {
        String name = "";
        if(params !=null && params instanceof List){
            List<ModelSpecificationInfo> list = (List<ModelSpecificationInfo>) params;
            List<String> collect = list.stream().map(s -> s.getSpecification()).collect(Collectors.toList());
            name = String.join(",", collect);
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchAdd.getCname() + ModelSpecification.getDesc(),
                        OperatorTypeDescEnum.batchAdd.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));
    }

    /**
     * 批量修改异常日志记录
     *
     * @param param
     */
    private void batchUpdateRecordMethod(Object param) {

    }

    /**
     * 批量删除异常日志记录
     *
     */
    private void batchRemoveRecordMethod(Object params) throws Exception {
        String name = "";
        if (params != null && params instanceof SpecificationIdsParam) {
            List<String> ids = ((SpecificationIdsParam) params).getIds();
            List<ModelSpecificationInfo> infos = doSelectByIds(ids);
            List<String> collect = infos.stream().map(s -> s.getSpecification()).collect(Collectors.toList());
            name = String.join(",", collect);
        }
        String nickName = SecurityUtils.getUser().getNickName();
        MessageSource messageSource = SpringUtil.getBean(MessageSource.class);
        logClientSimple.addBusinessLog(LogLevel.INFO.getId(), BusinessLogType.CMDB_MANAGE.getId(),
                messageSource.getMessage("mwCmdb-operation-log", new Object[]{nickName, DateUtils.now()
                        , BusinessLogType.CMDB_MANAGE.getCnName(), OperatorTypeDescEnum.batchRemove.getCname() + ModelSpecification.getDesc(),
                        OperatorTypeDescEnum.batchRemove.getCname() + name, Constants.OperationStatus.FAILED}, LocaleContextHolder.getLocale()));

    }
}
